home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Magazine / Online / httpproxy / src / net_as225.c < prev    next >
C/C++ Source or Header  |  1996-08-20  |  12KB  |  545 lines

  1. /*(( "Header" */
  2. /*
  3.  * $Id: net_as225.c,v 1.5 1996/08/11 22:25:15 mshopf Exp mshopf $
  4.  * (c) 1995-96 Matthias Hopf
  5.  *
  6.  * AS225/INet225/Surfer net protocol stack handler.
  7.  */
  8.  
  9. /*
  10.  * $Log: net_as225.c,v $
  11.  * Revision 1.5  1996/08/11  22:25:15  mshopf
  12.  * reworked debug messages.
  13.  *
  14.  * Revision 1.4  1996/07/17  16:42:42  mshopf
  15.  * added local hostname fetch.
  16.  *
  17.  * Revision 1.3  1996/06/03  04:08:19  mshopf
  18.  * added error messages.
  19.  * added hostname caching.
  20.  * added timeouts.
  21.  *
  22.  * Revision 1.2  1996/04/26  05:14:03  mshopf
  23.  * added blocking mode and rudimentary strerror.
  24.  * V0.13 alpha 5 fix.
  25.  *
  26.  * Revision 1.1  1996/04/24  17:41:16  mshopf
  27.  * Initial revision
  28.  *
  29.  * Revision 1.1  1996/04/24  03:20:13  mshopf
  30.  * Initial revision
  31.  *
  32.  */
  33.  
  34.  
  35. /*)) */
  36. /*(( "Includes" */
  37.  
  38. #include <sys/types.h>
  39. #include <sys/syslog.h>
  40. #include <sys/time.h>
  41. /* Uargl! can't compile without this (include file error...) */
  42. #  define SYS_TTYCHARS_H
  43. #include <sys/ioctl.h>
  44. #include <sys/socket.h>
  45. #include <sys/param.h>
  46.  
  47. #include <netdb.h>
  48. #include <netinet/in.h>
  49.  
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <stddef.h>
  53. #include <errno.h>
  54. #include <string.h>
  55. #include <stdarg.h>
  56.  
  57.  
  58. #include <proto/exec.h>
  59. #include <exec/types.h>
  60.  
  61. #include <ss/socket.h>
  62.  
  63. #include "net.h"
  64. #include "debug.h"
  65.  
  66. #define ioctl s_ioctl
  67. #define strcasecmp stricmp
  68. typedef int ioctl_t;
  69. typedef int sock_t;
  70. typedef int len_t;
  71.  
  72. /*)) */
  73. /*(( "Global variables" */
  74.  
  75. #define MIN_AS225VERSION  4             /* don't know necessary minimum version, but that's the version of the emulation socket.library... */
  76. #define MAX_HCACHESIZE 32
  77.  
  78. struct Library *SockBase = NULL;
  79. static fd_set ReadSet;
  80. static fd_set WriteSet;
  81. static fd_set ExceptSet;                /* on AS225 we need an additional exception set (see socket() description) */
  82. static sock_t ServerSocket = -1;
  83. static int  BlockingMode;
  84. static char *ErrorTxt = NULL;           /* extended error information */
  85.  
  86. struct HostCache {                                   /* no LRU so far... */
  87.              char Name [MAXHOSTNAMELEN];
  88.              struct in_addr Addr;
  89.          };
  90.  
  91. static struct HostCache HCache [MAX_HCACHESIZE];     /* initialised with 0s */
  92. static struct HostCache *HCacheNext = HCache;        /* next cache to be filled */
  93.  
  94. /*)) */
  95. static const char *as225_strerror (int ErrNo);
  96.  
  97. /*(( "addcache ()" */
  98.  
  99. static void addcache (const char *Name, struct in_addr Addr)
  100. {
  101.     if (strlen (Name) >= MAXHOSTNAMELEN)        /* just to be sure */
  102.     return;
  103.     debug (D_NET, ("adding cache for '%s'\n", Name));
  104.     HCacheNext->Addr = Addr;
  105.     strcpy (HCacheNext->Name, Name);
  106.     if ( ++HCacheNext >= &HCache [MAX_HCACHESIZE] )
  107.     HCacheNext = HCache;
  108. }
  109.  
  110.  
  111. /*)) */
  112. /*(( "getaddr ()" */
  113.  
  114. /* get host address by name, use cache */
  115.  
  116. static struct in_addr getaddr (const char *Name)
  117. {
  118.     struct hostent  *HostEnt;
  119.     struct in_addr r;
  120.     struct HostCache *c;
  121.  
  122.     for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
  123.     if (strcmp (c->Name, Name) == 0)
  124.         return (c->Addr);
  125.  
  126.     debug (D_NET, ("host '%s' not yet in cache\n", Name));
  127.     if ( (r.s_addr = inet_addr ((char *) Name)) +0 == -1)
  128.     {
  129.     if (! (HostEnt = gethostbyname ((char *) Name)) )
  130.     {
  131.         ErrorTxt = "Hostname lookup failed";
  132.         r.s_addr = (unsigned long) ~0;
  133.         return (r);
  134.     }
  135.     memmove (&r, HostEnt->h_addr, sizeof (r));
  136.     addcache (Name, *((struct in_addr *) HostEnt->h_addr));
  137.     }
  138.  
  139.     return (r);
  140. }
  141.  
  142.  
  143. /*)) */
  144. /*(( "getname ()" */
  145.  
  146. /* get host name by address, use cache */
  147. /* returns pointer to static buffer */
  148.  
  149. static const char *getname (struct in_addr Addr)
  150. {
  151.     struct hostent  *HostEnt;
  152.     struct HostCache *c;
  153.  
  154.     for (c = HCache; c < &HCache [MAX_HCACHESIZE]; c++)
  155.     if (c->Name [0] && memcmp (&c->Addr, &Addr, sizeof (Addr)) == 0)
  156.         return (c->Name);
  157.  
  158.     debug (D_NET, ("hostadr not yet in cache\n"));
  159.     if (! (HostEnt = gethostbyaddr ((caddr_t) &Addr, sizeof (struct in_addr), AF_INET)) )
  160.     return (inet_ntoa (Addr));
  161.     addcache (HostEnt->h_name, Addr);
  162.     return (HostEnt->h_name);
  163. }
  164.  
  165.  
  166. /*)) */
  167.  
  168. /*(( "my_syslog ()" */
  169.  
  170. /* syslog() is not available in AS225 and Surfer... */
  171.  
  172. static int my_syslog (int Pri, const char *Msg, ...)
  173. {
  174.     va_list Args;
  175.     char Buffer [512];
  176.  
  177.     va_start (Args, Msg);
  178.     vsprintf (Buffer, Msg, Args);
  179.     va_end   (Args);
  180.     return (s_syslog (Pri, Buffer));
  181. }
  182. /*)) */
  183. /*(( "init ()" */
  184.  
  185. /* Check for socketlibrary and initialise when everything's right */
  186. /* -> BlockMode = FALSE in nonblocking mode */
  187. /* <- TRUE on success, FALSE otherwise */
  188.  
  189. static int as225_init (int BlockMode)
  190. {
  191.     struct servent  *ServEnt;
  192.     struct hostent  *HostEnt;
  193.     static char     LocalHostName [MAXHOSTNAMELEN];
  194.  
  195.     debug (D_NET, ("AS225 networking module check\n"));
  196.     if (SockBase)
  197.     return TRUE;
  198.  
  199.     if (! (SockBase = OpenLibrary ("inet:libs/socket.library", MIN_AS225VERSION)))
  200.     if (! (SockBase = OpenLibrary ("socket.library", MIN_AS225VERSION)))
  201.         return FALSE;
  202.     debug (D_NET, ("AS225 networking ok\n"));
  203.     if (! (setup_sockets (FD_SETSIZE, &errno)))
  204.     {
  205.     CloseLibrary (SockBase);
  206.     SockBase = NULL;
  207.     return FALSE;
  208.     }
  209.     BlockingMode = BlockMode;
  210.  
  211.     /* get default 'http' protocoll port */
  212.     if (! (ServEnt = getservbyname ("http", "tcp")) )
  213.     my_syslog (LOG_WARNING, "unknown protocol 'http', using default port %d", DEFAULT_HTTPPORT);
  214.     else
  215.     {
  216.     NetAS225.StdHttpPort = ServEnt->s_port;
  217.     if (NetAS225.StdHttpPort != DEFAULT_HTTPPORT)
  218.         my_syslog (LOG_WARNING, "protocol 'http' doesn't use default port %d", DEFAULT_HTTPPORT);
  219.     }
  220.  
  221.     /* get local hostname */
  222.     if (gethostname (LocalHostName, MAXHOSTNAMELEN) < 0)
  223.     my_syslog (LOG_ERR, "cannot get local hostname");
  224.     else
  225.     {
  226.     NetAS225.HostName = LocalHostName;
  227.     if ( (HostEnt = gethostbyname (LocalHostName)) )
  228.     {
  229.         strncpy (LocalHostName, HostEnt->h_name, MAXHOSTNAMELEN-1);
  230.         LocalHostName [MAXHOSTNAMELEN-1] = '\0';
  231.     }
  232.     else
  233.         my_syslog (LOG_WARNING, "cannot resolve local hostname");
  234.     }
  235.  
  236.     return TRUE;
  237. }
  238.  
  239. /*)) */
  240. /*(( "exit ()" */
  241.  
  242. /* exit as225 protocol stack handler */
  243.  
  244. static void as225_exit (void)
  245. {
  246.     if (! SockBase)
  247.     return;
  248.     if (ServerSocket >= 0)
  249.     s_close (ServerSocket);
  250.     ServerSocket = -1;
  251.     cleanup_sockets ();
  252.     CloseLibrary (SockBase);
  253.     SockBase = NULL;
  254. }
  255.  
  256. /*)) */
  257. /*(( "select ()" */
  258.  
  259. /* wait for incoming / outgoing data */
  260. /* -> onNew:   called on accepted  socket, arguemnts: new fd, calling host's name (static) */
  261. /* -> onTOut:  called at least every MIN_TIMEOUT seconds, may be more often */
  262. /* <- TRUE: received Ctrl-C - FALSE: ok or error */
  263.  
  264. static int   as225_select (void (*onNew)(int, const char *), void (*onTOut)(void))
  265. {
  266.     struct sockaddr_in PeerIn;
  267.     len_t  PeerLen     = sizeof (PeerIn);
  268.     sock_t Peer;
  269.     ioctl_t on = 1;
  270.     struct timeval OutTime = { MIN_TIMEOUT, 0 };
  271.  
  272.     switch (select (FD_SETSIZE, &ReadSet, &WriteSet, &ExceptSet, &OutTime))
  273.     {
  274.     case 0:
  275.     onTOut ();
  276.     return FALSE;
  277.  
  278.     case -1:
  279.     if (errno == EINTR)
  280.         return TRUE;
  281.     syslog (LOG_ERR, "select failed: %s", as225_strerror (errno));
  282.     return TRUE;     /* and exit... */
  283.     }
  284.  
  285.     /* Check server socket for new connections */
  286.     if (FD_ISSET (ServerSocket, &ReadSet))
  287.     {
  288.     if ( (Peer = accept (ServerSocket, (struct sockaddr *) &PeerIn, &PeerLen)) )
  289.     {
  290. #ifdef FIOASYNC
  291.         if (ioctl (Peer, FIOASYNC, (caddr_t) &on) < 0)
  292.         {
  293.         my_syslog (LOG_ERR, "ioctl() failed for FIOASYNC: #%d#", errno);
  294.         s_close (Peer);
  295.         return FALSE;
  296.         }
  297. #endif
  298. #ifdef FIONBIO
  299.         if (ioctl (Peer, FIONBIO, (caddr_t) &on) < 0)
  300.         {
  301.         my_syslog (LOG_ERR, "ioctl() failed for FIONBIO: #%d#", errno);
  302.         s_close (Peer);
  303.         return FALSE;
  304.         }
  305. #endif
  306.         /* look up hostname here */
  307.         onNew ((int) Peer, getname (PeerIn.sin_addr));
  308.     }
  309.     else
  310.         my_syslog (LOG_ERR, "accept() failed: #%d#", errno);
  311.     }
  312.  
  313.     return FALSE;
  314. }
  315.  
  316. /*)) */
  317. /*(( "checkread/write ()" */
  318.  
  319. static int   as225_checkread (int Fd)
  320. {
  321.     /* on remote closure of the socket while reading is treated as a exception pending
  322.      * socket rather than a readable socket (see select ())*/
  323.     return (FD_ISSET (Fd, &ReadSet) || FD_ISSET (Fd, &ExceptSet));
  324. }
  325.  
  326. static int   as225_checkwrite (int Fd)
  327. {
  328.     return (FD_ISSET (Fd, &WriteSet));
  329. }
  330.  
  331. /*)) */
  332. /*(( "read/write ()" */
  333.  
  334. static int as225_read (int Fd, char *Buffer, int Size)
  335. {
  336.     int   i;
  337.     if ( (i = recv ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
  338.     ErrorTxt = "Read failed";
  339.     return i;
  340. }
  341.  
  342. static int as225_write (int Fd, char *Buffer, int Size)
  343. {
  344.     int   i;
  345.     if ( (i = send ((sock_t) Fd, Buffer, (len_t) Size, 0)) < 0)
  346.     ErrorTxt = "Write failed";
  347.     return i;
  348. }
  349.  
  350. /*)) */
  351. /*(( "server ()" */
  352.  
  353. /* open and set up server socket */
  354.  
  355. static int as225_server (int Port)
  356. {
  357.     struct sockaddr_in SockIn;
  358.     ioctl_t on = 1;
  359.  
  360.     if (ServerSocket)
  361.     s_close (ServerSocket);
  362.     if ( (ServerSocket = socket (PF_INET, SOCK_STREAM, 0)) < 0)
  363.     {
  364.     ErrorTxt = "socket() for serverport failed";
  365.     return FALSE;
  366.     }
  367.  
  368.     memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
  369.     SockIn.sin_family      = AF_INET;
  370.     SockIn.sin_addr.s_addr = INADDR_ANY;
  371.     SockIn.sin_port        = htons (Port);
  372.     if (bind (ServerSocket, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
  373.     {
  374.     ErrorTxt = "bind() failed for serverport";
  375.     return FALSE;
  376.     }
  377.  
  378.     if (! BlockingMode)
  379.     {
  380. #ifdef FIOASYNC
  381.     if (ioctl (ServerSocket, FIOASYNC, (caddr_t) &on) < 0)
  382.     {
  383.         ErrorTxt = "ioctl() failed for FIOASYNC";
  384.         return FALSE;
  385.     }
  386. #endif
  387. #ifdef FIONBIO
  388.     if (ioctl (ServerSocket, FIONBIO, (caddr_t) &on) < 0)
  389.     {
  390.         ErrorTxt = "ioctl() failed for FIONBIO";
  391.         return FALSE;
  392.     }
  393. #endif
  394.     }
  395.  
  396.     if (listen (ServerSocket, 5) < 0)
  397.     {
  398.     ErrorTxt = "listen() failed";
  399.     return FALSE;
  400.     }
  401.  
  402.     return TRUE;
  403. }
  404.  
  405. /*)) */
  406. /*(( "open ()" */
  407.  
  408. /* open and set up server socket */
  409. /* <- -1: error  Fd: otherwise */
  410.  
  411. static int as225_open (const char *Host, int Port)
  412. {
  413.     struct sockaddr_in SockIn;
  414.     ioctl_t on = 1;
  415.     sock_t Sock;
  416.  
  417.     memset ((char *) &SockIn, 0, sizeof (struct sockaddr_in));
  418.     SockIn.sin_family      = AF_INET;
  419.     SockIn.sin_port        = htons (Port);
  420.     if ( (SockIn.sin_addr  = getaddr (Host)).s_addr == ~0)
  421.     return -1;
  422.  
  423.     if ( (Sock = socket (PF_INET, SOCK_STREAM, 0)) < 0)
  424.     {
  425.     ErrorTxt = "socket() failed";
  426.     return -1;
  427.     }
  428.  
  429.     if (! BlockingMode)
  430.     {
  431. #ifdef FIOASYNC
  432.     if (ioctl (Sock, FIOASYNC, (caddr_t) &on) < 0)
  433.     {
  434.         ErrorTxt = "ioctl() failed for FIOASYNC";
  435.         s_close (Sock);
  436.         return -1;
  437.     }
  438. #endif
  439. #ifdef FIONBIO
  440.     if (ioctl (Sock, FIONBIO, (caddr_t) &on) < 0)
  441.     {
  442.         ErrorTxt = "ioctl() failed for FIONBIO";
  443.         s_close (Sock);
  444.         return -1;
  445.     }
  446. #endif
  447.     }
  448.  
  449.     if (connect (Sock, (struct sockaddr *) &SockIn, sizeof (struct sockaddr_in)) < 0)
  450.     if (errno != EINPROGRESS)
  451.     {
  452.         ErrorTxt = "connect() failed";
  453.         s_close (Sock);
  454.         return -1;
  455.     }
  456.  
  457.     errno = 0;
  458.     return Sock;
  459. }
  460.  
  461. /*)) */
  462. /*(( "close ()" */
  463.  
  464. /* open and set up server socket */
  465.  
  466. static void as225_close (int Fd)
  467. {
  468.     s_close ((sock_t) Fd);
  469. }
  470.  
  471. /*)) */
  472. /*(( "initfd/setfdread/write ()" */
  473.  
  474. /* <- Server: accept incoming requests */
  475.  
  476. static void as225_initfd (int Server)
  477. {
  478.     FD_ZERO (& ReadSet);
  479.     FD_ZERO (& WriteSet);
  480.     FD_ZERO (& ExceptSet);
  481.     if (Server)
  482.     FD_SET  (ServerSocket, & ReadSet);
  483. }
  484.  
  485. static void as225_setfdread (int Fd)
  486. {
  487.     FD_SET  ((sock_t) Fd, &ReadSet);
  488.     FD_SET  ((sock_t) Fd, &ExceptSet);
  489. }
  490.  
  491. static void as225_setfdwrite (int Fd)
  492. {
  493.     FD_SET  ((sock_t) Fd, &WriteSet);
  494. }
  495.  
  496. /*)) */
  497. /*(( "strerror ()" */
  498.  
  499. /* return enhanced error string */
  500.  
  501. static const char *as225_strerror (int ErrNo)
  502. {
  503.     static char Err [128];
  504.  
  505.     if (ErrorTxt)
  506.     {
  507.     if (ErrNo)
  508.         sprintf (Err, "%s: %s", ErrorTxt, strerror (ErrNo));
  509.     else
  510.         return (ErrorTxt);
  511.     ErrorTxt = NULL;
  512.     return (Err);
  513.     }
  514.     else if (ErrNo)
  515.     return (strerror (ErrNo));
  516.     return ("");
  517. }
  518.  
  519. /*)) */
  520. /*(( "Method dispatch table" */
  521.  
  522. netmethods_t NetAS225 = {
  523.                 "AS225/INet/Surfer",
  524.                 "unknown",
  525.                 FD_SETSIZE,
  526.                 DEFAULT_HTTPPORT,
  527.                 as225_init,
  528.                 as225_exit,
  529.                 as225_select,
  530.                 as225_checkread,
  531.                 as225_checkwrite,
  532.                 as225_read,
  533.                 as225_write,
  534.                 as225_server,
  535.                 as225_open,
  536.                 as225_close,
  537.                 as225_initfd,
  538.                 as225_setfdread,
  539.                 as225_setfdwrite,
  540.                 as225_strerror
  541.              };
  542.  
  543. /*)) */
  544.  
  545.